thumbnail
모던 JS Deep Dive - 4. 변수
Web Frontend / TIL / JavaScript
2023.03.16.

4.1 변수란 무엇인가? 왜 필요한가?

  • 복잡한 애플리케이션이라도 결국, 데이터를 입력받아 처리하고 결과를 출력하는 것이다. 변수는 프로그래밍에서 데이터를 관리하기 위한 핵심 개념.

  • 사람이 아래와 같은 식을 계산하기 위해, 10, 20, +기호를 알고 있어야 계산할 수 있듯이,

자바스크립트 엔진이 코드를 계산(평가 evaluation) 하려면, 10,20, +라는 기호(리터럴 literal과 연산자operator) 의 의미를 알고 있어야하며, 10+20이라는 식(표현식expression) 의 의미도 해석 (파싱parsing) 할 수 있어야 한다.

10 + 20
  • 위 식의 연산을 수행하기 위해 먼저 연산자의 좌변과 우변의 숫자 값 (피연산자,operand) 를 기억한다. 컴퓨터는 CPU를 통해 연산하고, 메모리를 통해 데이터를 기억한다.

  • 메모리(memory) 는 데이터 저장할 수 있는 메모리 셀(memory cell) 집합체

  • 메모리 셀 하나 크기1바이트(8비트) 이며, 메모리 셀 크기 단위로 데이터를 2진수로 저장하고 읽는다.

  • 셀은 고유의 메모리 주소(memory address)를 갖고 메모리 주소는 메모리 공간의 위치를 나타내며 메모리 크기만큼 정수로 표현된다. ex) 4GB 메모리는 0부터 4,294,967,294(0x00000000 ~ 0XFFFFFFFF)까지 메모리 주소를 갖는다.

    variable memory
  • 컴퓨터는 데이터 종류(숫자, 텍스트, 이미지, 동영상 등)와 상관없이 모든 데이터를 2진수로 처리하며 저장한다.

변수 필요성

  • 위의 식에서 10 과 20을 각각 메모리 공간에 저장하고 연산 결과인 30도 저장한다. 하지만, 이 결과 값을 재사용하기 위해선 저장된 메모리 주소를 통해 해당 메모리 공간에 직접 접근하는 방법 밖에 없다.

  • 하지만, 메모리 주소를 통해 값 직접 접근하는 방법은 실수로 운영체제 사용 값을 변경할 수 있어 치명적 오류가 발생될 수 있다. 따라서, 자바스크립트는 개발자의 직접적인 메모리 제어를 허용하지 않는다.

  • 프로그래밍 언어는 기억하고 싶은 값을 메모리에 저장하고 저장된 값을 재사용하기 위해 변수라는 매커니즘 제공

  • 변수(variable) - 하나의 값을 저장하기 위해 확보한 메모리 공간 자체 또는 그 메모리 공간을 식별하기 위해 붙인 이름, 값의 위치를 가리키는 상징적인 이름.

  • 변수는 언어의 컴파일러 또는 인터프리터에 의해 값이 저장된 메모리 공간의 주소로 치환되어 실행되어 개발자가 직접 메모리 주소를 통해 값 저장하고 참조할 필요가 없이 변수를 통해 안전하게 값에 접근 가능.

  • 10 + 20은 연산을 통해 새로운 값 30을 생성하고 메모리 공간에 저장된다.

  • 메모리 공간에 저장된 값을 식별할 수 있는 고유한 이름(result)을 변수 이름(또는 변수명). 변수에 저장된 값(30)을 변수값

    var result = 10 + 20;
variable identifier
  • 개발자의 의도를 나타내는 명확한 네이밍은 코드를 이해하기 쉽게 만들며 협업과 품질 향상에 도움을 주기 때문에 변수명은 잘 지어야 한다.

4.2 식별자

  • 식별자(identifier) - 변수 이름, 메모리 주소에 붙인 이름, 어떤 값을 구별해서 식별할 수 있는 고유한 이름, 메모리 상에 존재하는 어떤 값을 식별할 수 있는 이름
  • 식별자는 값이 아니라 메모리 주소를 기억하고 있다.
  • 선언(declaration)에 의해 자바스크립트 엔진에 식별자의 존재를 알린다.

4.3 변수 선언

  • 변수 선언(variable declaration) - 변수 생성하는 것. 값을 저장하기 위한 메모리 공간을 확보(allocate)하고 변수 이름과 확보된 메모리 공간의 주소를 연결(name binding)해서 값을 저장할 수 있게 준비하는 것.
  • 변수 사용을 위해서는 반드시 선언이 필요하다. 자바스크립트에서는 var, let, const 키워드.

cf. ES5 vs ES6 변수 선언 키워드

  • var는 블록 레벨 스코프(block-level-scope)를 지원하지 않고 함수 레벨 스코프(function-level-scope)를 지원하기 때문에 의도치 않게 전역 변수가 선언되어 부작용이 발생할 수 있다는 단점이 있다.
  • var 키워드 단점 보완을 위해 ES6에서 let, const 키워드를 도입했다.
  • var 키워드가 폐기(deprecated) 된 것은 아니지만, ES6이후 사양에서는 권장x

cf. 변수의 생성과정

  1. 선언 단계
  2. 초기화 단계
  3. 할당 단계
let name;
name = "HAESUNG";

var age;
age = 30;

const gender; // 선언에서 초기화가 없는 오류
gender = 'male'
  • var
    1. 선언 및 초기화 단계(undefined를 할당해주는 단계)
    2. 할당 단계
  • let
    1. 선언
    2. 초기화
    3. 할당
  • const
    1. 선언 + 초기화 + 할당

cf. 키워드(keyword)

  • 키워드는 자바스크립트 코드를 해석하고 실행하는 자바스크립트 엔진이 수행할 동작을 규정한 일종의 명령어. 자바스크립트 엔진은 키워드를 만나면 수행해야 할 약속된 동작을 수행. ex) var키워드 뒤에 변수 이름으로 새로운 변수 선언.

  • 변수 선언문은 아래와 같이 변수 이름을 등록하고 값을 저장할 메모리 공간을 확보한다.

var score // 변수 선언(변수 선언문)
variable declare
  • 변수 선언 후, 값 할당하지 않으면 확보된 메모리 공간에는 자바스크립트 엔진에 의해 undefined라는 값이 암묵적으로 할당되어 초기화 된다.(자바스크립트의 독특한 특징)
  • 자바스크립트 엔진의 변수 선언 2단계
    • 선언 단계 : 변수 이름을 등록해서 자바스크립트 엔진에 변수의 존재를 알린다.
    • 초기화 단계 : 값을 저장하기 위한 메모리 공간을 확보하고 암묵적으로 undefined를 할당해 초기화 한다.

cf. 변수 이름은 어디에 등록 되는가?

  • 변수 이름을 비롯한 모든 식별자실행 컨텍스트(execution context)에 등록 된다.
  • 실행 컨텍스트는 자바스크립트 엔진이 소스코드를 평가하고 실행하기 위한 필요 환경을 제공하고 코드 실행결과를 실제로 관리하는 영역
  • 자바스크립트 엔진은 실행컨텍스트를 통해 식별자와 스코프를 관리.
  • 변수 이름과 값은 실행컨텍스트 내 key / value 형식인 객체로 등록되어 관리 된다.
  • var 키워드를 사용한 변수 선언은 선언 단계와 초기화 단계가 동시 진행.
    • var score;는 선언 단계를 통해 변수 이름 score를 등록,
    • 초기화 단계를 통해 score 변수에 암묵적으로 undefined를 할당해 초기화
    • 초기화 단계를 거치지 않으면 확보된 메모리 공간에는 이전 애플리케이션이 사용했던 쓰레기 값(garbage value) 이 남아 있을 수 있다. 따라서, var 키워드로 선언한 변수는 암묵적으로 값을 할당하지 않아도 undefined 값으로 초기화를 하기 때문에 이런 위험으로부터 안전
    • cf. 초기화(initialization) - 변수가 선언된 이후 최초로 값을 할당하는 것
  • 변수를 사용하려면 반드시 선언이 필요하며 변수뿐만 아니라 모든 식별자도 동일
  • 만약 선언하지 않은 식별자에 접근하면 ReferenceError(참조 에러) 가 발생한다.
  • 참조 에러 - 식별자를 통해 값 참조 시, 자바스크립트 엔진이 등록된 식별자를 찾을 수 없을 때 발생하는 에러

4.4 변수 선언의 실행 시점과 변수 호이스팅

console.log(score); // undefined

var score; // 변수 선언문
  • 자바스크립트는 인터프리터에 의해 한줄 씩 순차적을 실행되므로 console.log(score)가 참조 에러가 발생할 것처럼 보인다. 하지만, undefined가 출력된다.
  • 이는 변수 선언이 소스코드가 한줄 씩 순차적으로 실행되는 시점, 즉 런타임(runtime)이 아니라 그 이전 단계에서 소스코드 평가 과정에서 모든 선언문을 먼저 실행하기 때문이다.
  • 변수 호이스팅(variable hoisting) - 변수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트 고유 특징
  • 변수 선언뿐 아니라 var, let, const, function ,function*, class 키워드 사용해서 선언하는 모든 식별자(변수, 함수, 클래스 등)는 호이스팅 된다.

4.5 값의 할당

  • 변수에 값을 할당(assignmnet)할 때는 할당 연산자 =를 사용
  • 할당 연산자는 우변의 값을 좌변의 변수에 할당
 var score; //변수 선언
score = 80; // 값의 할당
  • 변수 선언과 값의 할당을 하나의 문(statement)로 단축 표현 가능
var score = 80; // 변수 선언과 값 할당
  • 변수 선언과 값 할당을 2개의 문으로 나누어 각각 실행하기 때문에 변수 선언, 값 할당을 2개의 문으로 나눈 코드와 하나의 문으로 단축 표현한 코드 모두 동일하게 동작.

  • 변수 선언과 값 할당의 실행 시점이 다르다.

    • 변수 선언은 소스코드가 순차적으로 실행되는 시점인 런타임 이전에 먼저 실행

    • 값의 할당은 소스코드가 순차적으로 실행되는 시점인 런타임에 실행

      console.log(score); //undefined
      
      var score;  // 1. 변수선언
      score = 80; // 2. 값 할당
      
      console.log(score); // 80
  • 위에서 변수 값 할당할 때는 undefined가 저장된 공간이 아니라 새로운 메모리 공간을 확보하고 그곳에 할당 값을 저장한다. 이전 값 undefined가 저장되어 있던 메모리 공간을 지우고 그 공간에 할당 값을 새롭게 저장하는게 아니다.

    console.log(score); //undefined
    
    score = 80; // 값 할당
    var score;  // 변수 선언
    
    console.log(score); //80

4.6 값의 재할당

  • 재할당 - 이미 값 할당되어 있는 변수에 새로운 값을 또다시 할당하는 것
var score = 80;
score = 90;
  • var 키워드로 선언한 변수는 값을 재할당 할 수 있다.
  • var 키워드로 선언한 변수는 선언과 동시에 undefined로 초기화되므로 엄밀히 말하면 처음 값을 할당하는 것도 재할당이라고 볼 수 있다.
  • 상수(constant) - 값을 재할당할 수 없어서 변수에 저장된 값을 변경할 수 없는 값, 한번만 할당할 수 있는 변수

cf. const 키워드

  • ES6에서 도입된 const 키워드를 사용해 선언한 변수는 재할당 금지.

  • score 변수는 처음 undefined로 초기화 후, 80이 할당되고 90으로 재할당되면서 undefined와 80은 어떤 변수도 값으로 갖고 있지 않아 연결된 식별자가 없다. 이런 불필요한 값들은 가비지 콜렉터(garbage collector) 에 의해 메모리에서 자동 해제 된다.

variable reallocate

cf. 가비지 콜렉터

  • 애플리케이션이 할당한 메모리 공간을 주기적으로 검사하여 더이상 사용되지 않는 메모리(어떤 식별자도 참조하지 않는 메모리 공간)를 해제하는 기능.
  • 자바스크립트는 가비지 콜렉터를 내장하고 있는 매니지드 언어로서 가비지 콜렉터를 톨해 메모리 누수(memory leak)를 방지.

cf. 언 매니지드 언어(unmmanaged language)와 매니지드 언어(managed language)

  • 메모리 관리 방식에 따라 언매니지드 언어와 매니지드 언어로 분류
  • 언매니지드언어
    • C언어 같은 언매니지드 언어는 개발자가 명시적으로 메모리를 할당하고 해제하기 위해 malloc()과 free() 같은 저수준(low-level) 메모리 제어 기능을 제공한다.
    • 메모리 제어를 개발자가 주도할 수 있어 역량에 따라 최적 성능을 확보할 수 있다.
    • 하지만, 반대로 치명적 오류를 생산할 가능성도 있음.
  • 매니지드 언어
    • 메모리 할당 및 해제를 위한 메모리 관리 기능을 언어 차원에서 담당
    • 개발자의 직접적인 메모리 제어를 허용하지 않는다.
    • 사용되지 않는 메모리 해제는 가비지 콜렉터가 수행
    • 개발자의 역량에 의존하는 부분이 상대적으로 작아져 일정한 생산성을 확보할 수 있음
    • 하지만, 성능 면에서 어느 정도 손실 감수해야한다는 단점 존재

4.7 식별자 네이밍 규칙

  • 준수해야 할 식별자 네이밍 규칙

    • 식별자는 특수문자를 제외한 문자, 숫자, 언더스코어(_), 달러 기호($)를 포함할 수 있다.
    • 특수문자를 제외한 문자, 언더스코어(_), 달러기호($)로 시작해야한다. 숫자 시작 허용X
    • 예약어는 식별자로 사용 X
  • 변수 이름도 식별자이므로 네이밍 규칙을 준수해야 하지만, 다음과 같은 식별자는 변수 이름으로 사용 가능.

    var person, $elem, _name, first_name, val1;
  • ES5부터 식별자를 만들 때 유니코드 문자 허용. 하지만 알파벳외 유니코드 문자로 명명된 식별자 사용하는 것은 x

    var 이름, HAESUNG;
  • 네이밍 컨벤션(naming convention) 은 하나 이상의 영어 단어로 구성된 식별자 만들 때, 가독성 좋게 단어를 구분하기 위해 규정한 명명 규칙. 4가지 유형의 네이밍 컨벤션이 자주 사용

    // 카멜 케이스 (camelCase)
    var firstName;
    
    // 스네이크 케이스 (snake_case)
    var first_name;
    
    // 파스칼 케이스 (PascalCase)
    var FirstName;
    
    // 헝가리언 케이스 (typeHungarianCase) - 접두어에 자료형을 알아볼수 있게끔 표기하는 것
    var strFirstName; // type + identifier
    var $elem = document.getElementById('myId'); // DOM 노드
    var observable$ = fromEvent(document, 'click'); // RxJS 옵저버블
  • 어떤 네이밍 컨벤션을 사용해도 좋고 일관성 유지가 중요하지만,

자바스크립트에서 일반적으로 카멜 케이스 - 변수나 함수, 파스칼 케이스 - 생성자 함수, 클래스와 같이 사용한다. (ECMAScript 사양 정의 된 객체 함수도 카멜케이스와 파스칼 케이스 사용)

출처

  • 이웅모, 『모던 자바스크립트 Deep Dive 자바스크립트의 기본 개념과 동작 원리』, 위키북스(2020).
Thank You for Visiting My Blog, Have a Good Day 😄
© 2021 Developer Hae-sung, Powered By Gatsby.